package co.edu.unal.bioingenium.kbmed.knowledge;

import co.edu.unal.bioingenium.kbmed.knowledge.dao.KnowledgeSourceDAO;
import co.edu.unal.bioingenium.kbmed.knowledge.dao.KnowledgeSourceDAOFactory;
import co.edu.unal.bioingenium.kbmed.knowledge.hierarchy.HierarchyService;
import co.edu.unal.bioingenium.kbmed.knowledge.hierarchy.vo.Edge;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Alejandro Riveros Cruz
 */
public class KnowledgeService {

    /*
     * 
     */
    private KnowledgeSourceDAO knowledgeSourceDAO;
    /*
     * 
     */
    private HierarchyService hierarchyService;
    /*
     * 
     */
    private Map<String, String> conceptIdByDescriptorId;
    /*
     * 
     */
    private Map<String, String> categoryByConceptId;
    /*
     * 
     */
    private Map<String, String> termsByDescriptorId;
    /*
     * 
     */
    private Map<String, Set<String>> descriptorsIdsByConceptId;
    /*
     * 
     */
    private static KnowledgeService knowledgeServiceInstance;

    /**
     * 
     * @return
     */
    public static KnowledgeService getInstance() {
        if (knowledgeServiceInstance == null) {
            knowledgeServiceInstance = new KnowledgeService(KnowledgeSourceMetaData.getReference());
        }
        return knowledgeServiceInstance;
    }

    /**
     * 
     * @param knowledgeSourceMetaData 
     */
    public KnowledgeService(KnowledgeSourceMetaData knowledgeSourceMetaData) {
        knowledgeSourceDAO = KnowledgeSourceDAOFactory.getKnowledgeSourceDAO();
        hierarchyService = HierarchyService.getInstance();
        conceptIdByDescriptorId = knowledgeSourceDAO.getConceptIdByDescriptorId();
        Logger.getLogger(KnowledgeService.class.getName()).log(Level.INFO, "Load conceptIdByDescriptorId success.");
        categoryByConceptId = knowledgeSourceDAO.getCategoryByConceptId();
        Logger.getLogger(KnowledgeService.class.getName()).log(Level.INFO, "Load categoryByConceptId success.");
        descriptorsIdsByConceptId = knowledgeSourceDAO.getDescriptorsIdsByConceptId();
        Logger.getLogger(KnowledgeService.class.getName()).log(Level.INFO, "Load descriptorsIdsByConceptId success.");
        termsByDescriptorId = knowledgeSourceDAO.getTermsByDescriptorId();
        Logger.getLogger(KnowledgeService.class.getName()).log(Level.INFO, "Load termsByDescriptorId success.");
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public String getConceptIdForDescriptorId(String descriptorId) {
        return conceptIdByDescriptorId.get(descriptorId);
    }

    /**
     * 
     * @param conceptId 
     * @return
     */
    public Set<String> getDescriptorsIdsForConceptId(String conceptId) {
        return descriptorsIdsByConceptId.get(conceptId);
    }

    /**
     * 
     * @param conceptId 
     * @return
     */
    public String getCategoryForConceptId(String conceptId) {
        return categoryByConceptId.get(conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public String getCategoryForDescriptorId(String descriptorId) {
        return getCategoryForConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public String getTermForDescriptorId(String descriptorId) {
        return knowledgeSourceDAO.getTermForDescriptorId(descriptorId);
    }

    /**
     * 
     * @param descriptorIds
     * @return
     */
    public List<String> getConceptIdsFromDescriptorIds(List<String> descriptorIds) {
        List<String> conceptIds = new ArrayList<String>(descriptorIds);
        for (int i = 0; i < descriptorIds.size(); i++) {
            conceptIds.set(i, conceptIdByDescriptorId.get(descriptorIds.get(i)));
        }
        return conceptIds;
    }

    /**
     * 
     * @param conceptIds
     * @return
     */
    public List<String> getDescriptorIdsFromConceptIds(List<String> conceptIds) {
        List<String> descriptorIds = new ArrayList<String>();
        Set<String> tempSet;
        for (String conceptId : conceptIds) {
            tempSet = descriptorsIdsByConceptId.get(conceptId);
            //TODO is better to select the prefered desctriptor
            if (tempSet != null) {
                descriptorIds.add(tempSet.iterator().next());
            }
        }
        return descriptorIds;
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public Set<String> getTermsByConceptId(String conceptId) {
        Map<String, String> tempMap = knowledgeSourceDAO.getTermsForConcept(conceptId);
        Set<String> tempSet = new HashSet<String>();
        for (String descriptorId : tempMap.keySet()) {
            tempSet.add(tempMap.get(descriptorId));
        }
        return tempSet;
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public List<String> getPathToRootByConceptId(String conceptId) {
        List<Edge> edgeList = hierarchyService.getPathToRoot(conceptId, categoryByConceptId.get(conceptId));
        List<String> conceptIdList = new ArrayList<String>();
        for (Edge edge : edgeList) {
            conceptIdList.add(edge.getSource().getConceptId());
        }
        return conceptIdList;
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public List<String> getPathToRootByDescriptorId(String descriptorId) {
        return getPathToRootByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public Set<String> getDirectParentsByConceptId(String conceptId) {
        return hierarchyService.getDirectParents(categoryByConceptId.get(conceptId), conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public Set<String> getDirectParentsByDescriptorId(String descriptorId) {
        return getDirectParentsByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public Set<String> getDirectChildrensByConceptId(String conceptId) {
        return hierarchyService.getDirectChildrens(categoryByConceptId.get(conceptId), conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public Set<String> getDirectChildrensByDescriptorId(String descriptorId) {
        return getDirectChildrensByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public Set<String> getDirectSiblingsByConceptId(String conceptId) {
        return hierarchyService.getDirectSiblings(categoryByConceptId.get(conceptId), conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public Set<String> getDirectSiblingsByDescriptorId(String descriptorId) {
        return getDirectSiblingsByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public Set<String> getNeighborsByConceptId(String conceptId) {
        return hierarchyService.getNeighbors(categoryByConceptId.get(conceptId), conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public Set<String> getNeighborsByDescriptorId(String descriptorId) {
        return getNeighborsByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param conceptId
     * @return
     */
    public int getDeepInHierarchyByConceptId(String conceptId) {
        return hierarchyService.getDeepInHierarchy(categoryByConceptId.get(conceptId), conceptId);
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public int getDeepInHierarchyByDescriptorId(String descriptorId) {
        return getDeepInHierarchyByConceptId(conceptIdByDescriptorId.get(descriptorId));
    }

    /**
     * 
     * @param descriptorIds
     * @return
     */
    public Map<String, String> getTermsForDescriptorIds(Set<String> descriptorIds) {
        Map<String, String> termsMap = new HashMap<String, String>();
        for (String descriptorId : descriptorIds) {
            termsMap.put(descriptorId, termsByDescriptorId.get(descriptorId));
        }
        return termsMap;
    }

    /**
     * 
     * @param descriptorId
     * @return
     */
    public String getTermsForDescriptorId(String descriptorId) {
        return termsByDescriptorId.get(descriptorId);
    }
}
